package com.linran.utils.jackson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * key动态映射
 * 例1：
 * Q:future字段的key(day_20151011)是日期类型，会随着时间动态变化，序列化时如何解决?
 * A:通过Map映射解决
 * 例2:
 * Q:一个字段数据类型即是JSONArray又可以是JSONObject,如何处理
 * A:
 *  1.fastJson可以通过JSONObject进行处理(可以判断是jsonArray还是jsonObject)，再结合下面的代码统一将该字段转换为List<Map<String,Object>>类型
 *      Iterator iterator = joData.keys();                       // joData是JSONObject对象
 *      while(iterator.hasNext()){
 * 	        String key = iterator.next() + "";
 * 	        hashMap.put(key,joData.get(key));
 *      }
 *      arrayList.add(hashMap);
 *  2.jackson 通过JsonNode#isArray判断是否为数组，能够通过泛型结合TypeReference进行转换
 *
 * @author lin
 * @date 2020-08-12 9:29
 */
public class DynamicKeyMapping {
//    例1：
//    { "resultcode":"200","reason":"successed!",
//            "result":{
//        "sk":{
//            "temp":"24","wind_direction":"东北风","wind_strength":"2级","humidity":"28%","time":"17:38"
//        },
//        "today":{
//            "temperature":"15℃~26℃","weather":"多云转晴","wind":"东北风微风","week":"星期日","city":"桂林","date_y":"2015年10月11日","dressing_index":"舒适","dressing_advice":"建议着长袖T恤、衬衫加单裤等服装。年老体弱者宜着针织长袖衬衫、马甲和长裤。","uv_index":"弱","comfort_index":"","wash_index":"较适宜","travel_index":"较适宜","exercise_index":"较适宜","drying_index":""
//        },
//        "future":{
//            "day_20151011":{"temperature":"15℃~26℃","weather":"多云转晴","wind":"东北风微风","week":"星期日","date":"20151011"},
//            "day_20151012":{"temperature":"16℃~27℃","weather":"晴转多云","wind":"微风","week":"星期一","date":"20151012"},
//            "day_20151013":{"temperature":"16℃~26℃","weather":"多云转晴",,"wind":"微风","week":"星期二","date":"20151013"},
//            "day_20151014":{"temperature":"17℃~27℃","weather":"晴","wind":"北风微风","week":"星期三","date":"20151014"},
//            "day_20151015":{"temperature":"17℃~28℃","weather":"晴","wind":"北风微风","week":"星期四","date":"20151015"},
//            "day_20151016":{"temperature":"17℃~30℃","weather":"晴","wind":"北风微风","week":"星期五","date":"20151016"},
//            "day_20151017":{"temperature":"17℃~30℃","weather":"晴","wind":"北风微风","week":"星期六","date":"20151017"}
//        }
//    },
//        "error_code":0
//    }


//    例2:
//    {"code":"1","name":"kongge","age":22,"data":[{"userId":"123","userPwd":"456"},{"userId":"321","userPwd":"789"}]}  // @1
//    {"code":"1","name":"ggg","age":23,"data":{"like":"game","fruit":"apple"}}                                         // @2
//    {"code":"1","name":"ggg","age":24,"data":{"sex":"man","like":"play","fruit":"banana"}}                            // @3
//    {"code":"0","error":"I'm sorry!"}

    public static void main(String[] args) throws IOException {
        //例1:
        String json = "{\"resultcode\":\"200\",\"reason\":\"successed!\",\"result\":{\"sk\":{\"temp\":\"24\",\"wind_direction\":\"东北风\",\"wind_strength\":\"2级\",\"humidity\":\"28%\",\"time\":\"17:38\"},\"today\":{\"temperature\":\"15℃~26℃\",\"weather\":\"多云转晴\",\"wind\":\"东北风微风\",\"week\":\"星期日\",\"city\":\"桂林\",\"date_y\":\"2015年10月11日\",\"dressing_index\":\"舒适\",\"dressing_advice\":\"建议着长袖T恤、衬衫加单裤等服装。年老体弱者宜着针织长袖衬衫、马甲和长裤。\",\"uv_index\":\"弱\",\"comfort_index\":\"\",\"wash_index\":\"较适宜\",\"travel_index\":\"较适宜\",\"exercise_index\":\"较适宜\",\"drying_index\":\"\"},\"future\":{\"day_20151011\":{\"temperature\":\"15℃~26℃\",\"weather\":\"多云转晴\",\"wind\":\"东北风微风\",\"week\":\"星期日\",\"date\":\"20151011\"},\"day_20151012\":{\"temperature\":\"16℃~27℃\",\"weather\":\"晴转多云\",\"wind\":\"微风\",\"week\":\"星期一\",\"date\":\"20151012\"},\"day_20151013\":{\"temperature\":\"16℃~26℃\",\"weather\":\"多云转晴\",\"wind\":\"微风\",\"week\":\"星期二\",\"date\":\"20151013\"},\"day_20151014\":{\"temperature\":\"17℃~27℃\",\"weather\":\"晴\",\"wind\":\"北风微风\",\"week\":\"星期三\",\"date\":\"20151014\"},\"day_20151015\":{\"temperature\":\"17℃~28℃\",\"weather\":\"晴\",\"wind\":\"北风微风\",\"week\":\"星期四\",\"date\":\"20151015\"},\"day_20151016\":{\"temperature\":\"17℃~30℃\",\"weather\":\"晴\",\"wind\":\"北风微风\",\"week\":\"星期五\",\"date\":\"20151016\"},\"day_20151017\":{\"temperature\":\"17℃~30℃\",\"weather\":\"晴\",\"wind\":\"北风微风\",\"week\":\"星期六\",\"date\":\"20151017\"}}},\"error_code\":0}";
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        Response response = objectMapper.readValue(json, Response.class);
        System.out.println("serilizer finished!");
        //例2:
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        String jsonStr1 = "{\"code\":\"1\",\"name\":\"kongge\",\"age\":22,\"data\":[{\"userId\":\"123\",\"userPwd\":\"456\"},{\"userId\":\"321\",\"userPwd\":\"789\"}]}";
        Model<Model<List<Map<String, Object>>>> model1 = objectMapper.readValue(jsonStr1, new TypeReference<Model<List<Map<String, Object>>>>(){});
        String jsonStr2 = "{\"code\":\"1\",\"name\":\"ggg\",\"age\":23,\"data\":{\"like\":\"game\",\"fruit\":\"apple\"}}";
        Model<Map<String, Object>> model2 = objectMapper.readValue(jsonStr2, new TypeReference<Model<Map<String, Object>>>(){});
        String jsonStr3 = "{\"code\":\"1\",\"name\":\"ggg\",\"age\":24,\"data\":{\"sex\":\"man\",\"like\":\"play\",\"fruit\":\"banana\"}}";
        Model<Map<String, Object>> model3 = objectMapper.readValue(jsonStr3, new TypeReference<Model<Map<String, Object>>>(){});

        //补充：
        //fastJson判断某一个key的value是JSONArray还是JSONObject 可以通过debug查看obj具体类型
        Object obj = JSON.parseObject(jsonStr2).get("data");
        if (obj instanceof JSONObject){
            System.out.println("json object");
        } else if (obj instanceof JSONArray){
            System.out.println("json array");
        }
    }

    /**
     * 统计返回格式Model<List<Map<String, Object>>>
     *
     * 不适用多个字段jsonObject与jsonArray
     * @param objectMapper
     * @param json
     * @return
     */
    public static Model<List<Map<String, Object>>> parseModel(ObjectMapper objectMapper,String json){
        try {
            String[] data = json.split("data");
            //data数组
            if (data[1].startsWith("[")) {
                return objectMapper.readValue(json, new TypeReference<Model<List<Map<String, Object>>>>(){});
            //data单个对象
            } else {
                //先用Map处理
                Model<Map<String, Object>> model = objectMapper.readValue(json, new TypeReference<Model<Map<String, Object>>>() {});
                //转换为统计List<Map<String,Object>>格式
                Model<List<Map<String, Object>>> listModel = new Model<>();
                BeanUtils.copyProperties(model, listModel);
                listModel.setData(List.of(model.getData()));
                return listModel;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

@Getter
@Setter
class Result {
    private Sk sk;
    private Today today;
    /**
     * key为string,value为FutureDay对象！！
     */
    private Map<String, FutureDay> future;
}

@Setter
@Getter
class FutureDay {
    private String temperature;
    private String weather;
    private String wind;
    private String week;
    private String date;
}

@Getter
@Setter
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
class Sk {
    private String temp;
    private String windDirection;
    private String windStrength;
    private String humidity;
    private String time;
}

@Getter
@Setter
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
class Today {
    private String temperature;
    private String weather;
    private String week;
    private String wind;
    private String city;
    private String dateY;
    private String dressingIndex;
    private String dressingAdvice;
    private String uvIndex;
    private String comfortIndex;
    private String washIndex;
    private String travelIndex;
    private String exerciseIndex;
    private String dryingIndex;
}

@Setter
@Getter
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
class Response {
    private String resultcode;
    private String reason;
    private String errorCode;
    private Result result;
}

@Setter
@Getter
//List<Map<String, Object>>
class Model<T> {
    private String code;
    private String name;
    private Integer age;
    private T data;
}